﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace StockCrawler
{
    public class ForeignInfoCrawler
    {
        public void Run()
        {
            Console.WriteLine("Retrieving foreign history data...");

            if (CrawlingContext.Current.StockList != null)
            {
                foreach (var symbol in CrawlingContext.Current.StockList)
                {
                    DoCrawling(symbol);
                }
            }

            Console.WriteLine("Finished retrieving foreign history data.");
        }

        private void DoCrawling(string symbol)
        {
            IList<ForeignTransactionHistory> foreignTransactionHistoryList = RetrieveForeignTransactionHistoryData(symbol);
            SaveForeignTransactionHistoryData(foreignTransactionHistoryList);
        }

        private IList<ForeignTransactionHistory> RetrieveForeignTransactionHistoryData(string symbol)
        {
            String rawData = RetrieveRawData(symbol);

            return ParseData(symbol, rawData);
        }

        private string RetrieveRawData(string symbol)
        {
            try
            {
                HttpWebRequest myWebRequest = (HttpWebRequest)WebRequest.Create(String.Format("http://cafef.vn/Lich-su-giao-dich-Symbol-{0}/Trang-1-0-tab-3.chn", symbol.ToUpper()));
                using (HttpWebResponse siteResponse = (HttpWebResponse)myWebRequest.GetResponse())
                {
                    using (Stream streamResponse = siteResponse.GetResponseStream())
                    {
                        using (StreamReader reader = new StreamReader(streamResponse, Encoding.UTF8))
                        {
                            var stockData = reader.ReadToEnd();
                            stockData = stockData.Replace(Environment.NewLine, String.Empty)
                                                 .Replace("&nbsp;", String.Empty);

                            Regex regex = new Regex(@"\<tr id="".+rptData((?!(\<\/tr\>)).)*(\<\/tr\>)");
                            var stockInfoList = regex.Matches(stockData);

                            if (stockInfoList.Count > 0)
                            {
                                return stockInfoList[stockInfoList.Count - 1].Value;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }

            return string.Empty;
        }

        private IList<ForeignTransactionHistory> ParseData(string symbol, string rawData)
        {
            if (String.IsNullOrWhiteSpace(rawData))
            {
                return null;
            }

            var foreignTransactionData = RefineData(rawData);

            XDocument document = XDocument.Parse(foreignTransactionData);
            IList<ForeignTransactionHistory> foreignTransactionHistoryList = new List<ForeignTransactionHistory>();

            foreach (var transactionItem in document.Root.Elements("tr"))
            {
                var valueList = transactionItem.Elements("td").ToList();
                foreignTransactionHistoryList.Add(new ForeignTransactionHistory()
                {
                    Symbol = symbol.ToUpper(),
                    TransactionDate = CrawlingUtility.ParseDate(valueList[0].Value),
                    TransactionVolume = CrawlingUtility.ParseVolume(valueList[1].Value),
                    TransactionValue = CrawlingUtility.ParseNumber(valueList[2].Value),
                    Change = CrawlingUtility.ParseNumber(valueList[3].Value),
                    BiddingVolume = CrawlingUtility.ParseVolume(valueList[4].Value),
                    BiddingValue = CrawlingUtility.ParseNumber(valueList[5].Value),
                    AskingVolume = CrawlingUtility.ParseVolume(valueList[6].Value),
                    AskingValue = CrawlingUtility.ParseNumber(valueList[7].Value),
                    RemainingRoom = CrawlingUtility.ParseVolume(valueList[8].Value),
                    Owning = CrawlingUtility.ParseNumber(valueList[9].Value.Replace("%", String.Empty))
                });
            }

            return foreignTransactionHistoryList.OrderByDescending(f => f.TransactionDate).ToList();
        }

        private string RefineData(string rawData)
        {
            Regex regex = new Regex(@"\<span((?!(\<\/span\>)).)*\<\/span\>");
            rawData = regex.Replace(rawData, String.Empty);
            regex = new Regex(@"\<img((?!(\>)).)*\>");
            rawData = regex.Replace(rawData, String.Empty);

            rawData = String.Format("<ForeignTransactionData>{0}</ForeignTransactionData>", rawData);

            return rawData;
        }

        private void SaveForeignTransactionHistoryData(IList<ForeignTransactionHistory> foreignTransactionHistoryList)
        {
            if (foreignTransactionHistoryList != null && foreignTransactionHistoryList.Count > 0)
            {
                using (var context = new StockBiz())
                {
                    foreach (var foreignTransactionHistory in foreignTransactionHistoryList)
                    {
                        if (context.ForeignTransactionHistories.Where(f
                                                            =>
                                                                f.Symbol == foreignTransactionHistory.Symbol
                                                                       && f.TransactionDate == foreignTransactionHistory.TransactionDate
                                                        ).Count() <= 0)
                        {
                            foreignTransactionHistory.ID = Guid.NewGuid();
                            context.ForeignTransactionHistories.AddObject(foreignTransactionHistory);
                        }
                        else
                        {
                            break;
                        }
                    }

                    context.SaveChanges();
                }
            }
        }
    }
}
